package org.hepeng.fabric.contract.api;


import org.hepeng.fabric.contract.api.annotation.ContractAPI;
import org.hepeng.fabric.contract.api.annotation.TxFunction;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author he peng
 * @date 2022/3/23
 */
public abstract class ContractResolver {


    public static Optional<ContractDefinition> resolve(Class<?> cls) {

        ContractAPI contractAPIAtn = cls.getDeclaredAnnotation(ContractAPI.class);
        if (Objects.isNull(contractAPIAtn)) {
            return Optional.empty();
        }

        ContractDefinition contract = new ContractDefinition()
                .setChainCodeName(contractAPIAtn.chainCode())
                .setName(contractAPIAtn.name())
                .setContractInterface(cls);

        Set<TxFunctionDefinition> txFunctions = new HashSet<>();

        for (Method method : cls.getMethods()) {
            TxFunction txFunctionAtn = method.getDeclaredAnnotation(TxFunction.class);
            if (Objects.nonNull(txFunctionAtn)) {

                TxFunctionDefinition txFunction = new TxFunctionDefinition()
                        .setName(method.getName())
                        .setArgTypes(method.getParameterTypes())
                        .setQuery(Objects.equals(TxFunction.Type.QUERY, txFunctionAtn.type()))
                        .setSubmit(Objects.equals(TxFunction.Type.SUBMIT, txFunctionAtn.type()))
                        .setMethod(method)
                        .setEvents(Arrays.stream(txFunctionAtn.events()).collect(Collectors.toList()));

                txFunctions.add(txFunction);

            }

        }

        contract.setTxFunctions(txFunctions);

        return Optional.of(contract);

    }
}
